<?php
// +--------------------------------------------------------------------------------------------------------------------
// | 本文件是《FastChat》的一部分，所有代码、文字、图片、样式、风格等版权归作者所有，如有复制、仿冒、抄袭、盗用，FastAdmin和作者将追究法律责任
// +--------------------------------------------------------------------------------------------------------------------
// | @作者: 妙码生花 <1094963513@qq.com>
// +--------------------------------------------------------------------------------------------------------------------
// | @唯一授权链接: https://www.fastadmin.net/store/fastchat.html
// +--------------------------------------------------------------------------------------------------------------------

namespace addons\fastchat\library;

use think\Db;
use think\Hook;
use app\common\model\Config;
use GatewayWorker\Lib\Gateway;

/**
 *
 */
class Common
{

    function __construct()
    {

    }

    /**
     * 直接添加会话
     * @param string $user_id 会话对象
     * @return array
     */
    public static function add_session($user_id)
    {
        $user = explode('||', $_SESSION['user_id']);
        if($user[0] != 1){
            $info = Db::name('admin')->alias('a')->join('auth_group_access b','a.id = b.uid')->where('a.id',$user[0])->where('b.group_id',10)->find();
            if(!$info) return false;
        }
        $session_user = self::user_info($user_id);

        $session = [
            'user_id'         => $_SESSION['user_id'],
            'session_type'    => $session_user['session_type'],
            'session_user_id' => $session_user['id'],
            'createtime'      => time(),
            'deletetime'      => null,
            'deleteuser'      => ''
        ];

        Db::name('fastchat_session')->insert($session);
        $session['id'] = Db::name('fastchat_session')->getLastInsID();

        return $session;
    }

    /**
     * 获取一个用户的基本信息
     * @param string $user 待标识符的用户id
     * @return array
     */
    public static function user_info($user)
    {
        $user = explode('||', $user);

        if (isset($user[1])) {

            if ($user[1] == 'user' || $user[1] == 'admin') {

                $user_info = Db::name($user[1])->where('id', $user[0])->find();

                $user_info['source']       = $user[1];
                $user_info['session_type'] = ($user[1] == 'user') ? 0 : 1;
            } elseif ($user[1] == 'tourists') {

                $user_info = Db::name('fastchat_tourists')->where('id', $user[0])->find();

                $user_info['source']       = $user[1];
                $user_info['session_type'] = 2;
            } elseif ($user[1] == 'service_user') {
                $user_info                 = Db::name('fastchat_service_user')->where('id', $user[0])->find();
                $user_info['session_type'] = 5;
            }

            if (!isset($user_info) || !isset($user_info['id'])) {
                $user_info['id']           = $user[0];
                $user_info['source']       = 'unknown';
                $user_info['nickname']     = '未知用户' . $user[0];
                $user_info['avatar']       = false;
                $user_info['session_type'] = 4;
            }

            $user_info['avatar'] = self::img_src_fill($user_info['avatar']);
        } else {
            $user_info['id']           = $user[0];
            $user_info['source']       = 'none';
            $user_info['nickname']     = '未知' . $user[0];
            $user_info['avatar']       = self::img_src_fill(false);
            $user_info['session_type'] = 3;
        }

        return $user_info;
    }

    /**
     * 获取图片的完整地址
     * @param string $src 待处理的图片
     * @return string
     */
    public static function img_src_fill($src)
    {
        $upload = Config::upload();
        Hook::listen("upload_config_init", $upload);
        $view_cdn = config('view_replace_str.__CDN__');
        $view_cdn = $view_cdn ?: cdnurl('', true);
        $domain   = $upload['cdnurl'] ?? $view_cdn;
        return $src ? cdnurl($src, $domain) : $domain . '/assets/img/avatar.png';
    }

    /**
     * 发送消息
     * @param string $user_id         带标识符的发送人
     * @param string $session_user_id 带标识符的接受人
     * @param string $message         消息内容
     * @return array
     */
    public static function send_message($user_id, $session_user_id, $data)
    {
        // 检查黑名单
        $blacklist = Db::name('fastchat_blacklist')
            ->where('user_id', $session_user_id)
            ->where('session_user_id', $user_id)
            ->value('id');

        if ($blacklist) {
            return ['msgtype' => 'send_message', 'code' => 0, 'msg' => '发送失败,对方已屏蔽您的发言！'];
        }

        // 检查是否有会话，没有则添加，有则直接发送消息
        $user         = self::user_info($user_id);
        $session_user = self::user_info($session_user_id);

        $session = Db::name('fastchat_session')->where(function ($query) use ($user_id, $session_user) {

            $query->where('user_id', $user_id)
                ->where('session_type', $session_user['session_type'])
                ->where('session_user_id', $session_user['id']);

        })->whereOr(function ($query) use ($session_user_id, $user) {

            $query->where('user_id', $session_user_id)
                ->where('session_type', $user['session_type'])
                ->where('session_user_id', $user['id']);

        })
            ->find();

        if (!$session) {

            $session = [
                'user_id'         => $user_id,
                'session_type'    => $session_user['session_type'],
                'session_user_id' => $session_user['id'],
                'createtime'      => time(),
                'deletetime'      => null,
                'deleteuser'      => ''
            ];

            Db::name('fastchat_session')->insert($session);
            $session['id'] = Db::name('fastchat_session')->getLastInsID();
        }

        $message_text = strip_tags($data['content'], '<br><div><img><a>');

        $message = [
            'session_id' => $session['id'],
            'sender'     => $user_id,
            'message'    => $message_text,
            'createtime' => time(),
            'kf_id'=>$data['kf_id'],
            'admin_id'=>$data['admin_id'],
            'admin_name'=>$data['admin_name'],
            'type'=>$data['type'],

        ];

        if (Db::name('fastchat_record')->insert($message)) {

            $message['record_id'] = Db::name('fastchat_record')->getLastInsID();//消息记录ID

            // 确定会话状态
            Db::name('fastchat_session')->where('id', $session['id'])->update(['deleteuser' => '', 'deletetime' => null, 'createtime' => time()]);

            if (Gateway::isUidOnline($session_user_id)) {

                // 加上发信人的信息
                $message['avatar']       = $user['avatar'];
                $message['nickname']     = $user['nickname'];
                $message['session_user'] = $user_id;
                $message['online']       = 1;

                $message['id'] = $message['session_id'];// 兼容前台
                unset($message['session_id']);

                $message['last_message'] = self::session_message($message_text);
                $message['last_time']    = self::format_time(null);
                $message['message']      = htmlspecialchars_decode($message['message']);

                // 查询当前用户发送的未读消息条数
                $message['unread_msg_count'] = Db::name('fastchat_record')
                    ->where('session_id', $message['id'])
                    ->where('sender', $user_id)
                    ->where('status', 0)
                    ->count('id');

                $message['sender'] = 'you';

                Gateway::sendToUid($session_user_id, json_encode(['msgtype' => 'new_message', 'data' => $message]));
            } else {
                // 检查是否有绑定服务号
                if ($session_user['session_type'] == 1) {

                    $service_user = Db::name('fastchat_service_user')
                        ->where('admin_id', $session_user['id'])
                        ->where('status', '1')
                        ->where('deletetime', null)
                        ->find();

                    if ($service_user) {
                        $msg = '对方正使用服务账号【' . $service_user['nickname'] . '】接收消息，您的消息可能无法被对方查看！';
                        return ['msgtype' => 'send_message', 'code' => 0, 'msg' => $msg];
                    }
                }
            }

            return ['msgtype' => 'send_message', 'code' => 1];
        } else {
            return ['msgtype' => 'send_message', 'code' => 0, 'msg' => '发送失败,请重试！'];
        }

    }

    /**
     * 格式化消息-将图片和连接用文字代替
     * @param string $message 消息内容
     * @return string
     */
    public static function session_message($message)
    {
        $message = htmlspecialchars_decode($message);
        $message = preg_replace("/<img(.*)>/", '[图片]', $message);
        return preg_replace("/<a(.*)<\/a>/", '[链接]', $message);
    }

    /**
     * 格式化时间
     * @param ?int $time 时间戳
     * @return string
     */
    public static function format_time($time = null)
    {

        $now_time = time();
        $time     = ($time === null || $time > $now_time || $time == $now_time) ? $now_time + 1 : intval($time);

        $t = $now_time - $time; //时间差 （秒）
        $y = date('Y', $time) - date('Y', $now_time);//是否跨年

        switch ($t) {
            case $t <= 0:
                $text = '刚刚';
                break;
            case $t < 60:
                $text = $t . '秒前'; // 一分钟内
                break;
            case $t < 60 * 60:
                $text = floor($t / 60) . '分钟前'; //一小时内
                break;
            case $t < 60 * 60 * 24:
                $text = floor($t / (60 * 60)) . '小时前'; // 一天内
                break;
            case $t < 60 * 60 * 24 * 3:
                $text = floor($time / (60 * 60 * 24)) == 1 ? '昨天' . date('H:i', $time) : '前天' . date('H:i', $time); //昨天和前天
                break;
            case $t < 60 * 60 * 24 * 30:
                $text = date('m-d H:i', $time); //一个月内
                break;
            case $t < 60 * 60 * 24 * 365 && $y == 0:
                $text = date('m-d', $time); //一年内
                break;
            default:
                $text = date('Y-m-d', $time); //一年以前
                break;
        }

        return $text;
    }

    /**
     * 用户token加密
     * @param string $token 待加密的token
     */
    public static function getEncryptedToken($token)
    {
        $token_config = \think\Config::get('token');

        $config = array(
            // 缓存前缀
            'key'      => $token_config['key'],
            // 加密方式
            'hashalgo' => $token_config['hashalgo']
        );

        return hash_hmac($config['hashalgo'], $token, $config['key']);
    }

    /**
     * 检查用户身份
     * @param ?string $user_cookie 用户cookie
     * @param int     $user_id     用户ID直接登录
     */
    public static function check_fa_user($user_cookie = null, $user_id = 0)
    {
        if ($user_cookie && !$user_id) {
            $cookie_httponly = config('cookie.httponly');
            if (!$cookie_httponly) {
                $user_id = Db::name('user_token')->where('token', Common::getEncryptedToken($user_cookie))->value('user_id');
            } else {
                list($id, $key) = explode('|', $user_cookie);
                $user_token_list = Db::name('user_token')
                    ->where('user_id', $id)
                    ->where('expiretime', '>', time())
                    ->select();
                foreach ($user_token_list as $user_token) {
                    $sign     = $user_token['token'] . 'fastchat_user_sign_additional';
                    $user_key = md5(md5($id) . md5($sign));
                    if ($user_key == $key) {
                        $user_id = $id;
                        break;
                    } else {
                        $user_id = false;
                    }
                }

            }
        }

        if ($user_id) {
            $user_info = Db::name('user')
                ->field('password,salt,token', true)
                ->where('id', $user_id)
                ->find();
            if ($user_info) {
                $user_info['user_id'] = $user_info['id'] . '||user';
                return $user_info;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 检查管理员身份
     * @param string $keeplogin 管理员cookie信息
     * @param int    $admin_id  管理员ID直接登录
     * @return array
     */
    public static function check_admin($keeplogin, $admin_id = 0)
    {
        if ($admin_id) {
            $admin = Db::name('admin')->field(['password', 'salt'], true)->where('id', $admin_id)->find();
            if (!$admin) {
                return false;
            }
        } else {
            list($id, $keeptime, $expiretime, $key) = explode('|', $keeplogin);

            if ($id && $keeptime && $expiretime && $key && $expiretime > time()) {

                $admin = Db::name('admin')->where('id', $id)->find();

                if (!$admin || !$admin['token']) {
                    return false;
                }

                //token有变更
                $sign = $id . 'fastchat_admin_sign_additional';
                if ($key != md5(md5($sign) . md5($keeptime) . md5($expiretime) . $admin['token'])) {
                    return false;
                }
            } else {
                return false;
            }
        }


        // 检查是否与服务号绑定
        $service_user = Db::name('fastchat_service_user')
            ->where('admin_id', $admin['id'])
            ->where('status', '1')
            ->where('deletetime', null)
            ->find();

        if ($service_user) {
            $service_user['username'] = $service_user['nickname'];
            $service_user['user_id']  = $service_user['id'] . '||service_user';
            $service_user['token']    = $admin['token'];
            return $service_user;
        }

        $admin['user_id']  = $admin['id'] . '||admin';
        $admin['admin_id'] = $admin['id'];// 和服务号字段统一

        return $admin;
    }

    /**
     * 将游客的会话转到用户
     * @param string $tourists 游客的cookie信息
     * @param string $user_id  带标识符的用户id
     * @return bool
     */
    public static function tourists_to_login($tourists, $user_id)
    {
        $user          = self::user_info($user_id);//登录人信息
        $tourists_info = self::check_tourists($tourists);//游客信息

        if (!$tourists_info) {
            return;
        }

        // 查出游客的所有会话-》把 user_id 没有的会话转给 user_id
        $session_list = Db::name('fastchat_session')
            ->where(function ($query) use ($tourists_info) {
                $query->where('user_id', $tourists_info['user_id']);
            })->whereOr(function ($query) use ($tourists_info) {
                $query->where('session_user_id', $tourists_info['id'])->where('session_type', 2);
            })
            ->order('createtime desc')
            ->select();

        foreach ($session_list as $value) {

            $session_user      = Common::session_user($value, $tourists_info['user_id']);//本会话的会话对象
            $session_user_info = Common::user_info($session_user);//会话对象信息

            $session = Db::name('fastchat_session')->where(function ($query) use ($user_id, $session_user_info) {

                $query->where('user_id', $user_id)
                    ->where('session_type', $session_user_info['session_type'])
                    ->where('session_user_id', $session_user_info['id']);

            })->whereOr(function ($query) use ($session_user, $user) {

                $query->where('user_id', $session_user)
                    ->where('session_type', $user['session_type'])
                    ->where('session_user_id', $user['id']);

            })
                ->find();

            if (!$session) {

                // 将此会话转给用户
                if ($value['user_id'] == $tourists_info['user_id']) {
                    Db::name('fastchat_session')
                        ->where('id', $value['id'])
                        ->update(['user_id' => $user_id]);
                } else {
                    Db::name('fastchat_session')
                        ->where('id', $value['id'])
                        ->update(['session_user_id' => $user['id'], 'session_type' => $user['session_type']]);
                }

                Db::name('fastchat_record')
                    ->where('session_id', $value['id'])
                    ->where('sender', $tourists_info['user_id'])
                    ->update(['sender' => $user_id]);
            }
        }

        return true;
    }

    /**
     * 检查游客身份
     * @param string $tourists 游客的cookie信息
     * @return array|bool
     */
    public static function check_tourists($tourists)
    {
        list($id, $keeptime, $expiretime, $key) = explode('|', $tourists);

        if ($id && $keeptime && $expiretime && $key && $expiretime > time()) {

            $tourists = Db::name('fastchat_tourists')->where('id', $id)->find();

            if (!$tourists || !$tourists['token']) {
                return false;
            }

            //token有变更
            if ($key != md5(md5($id) . md5($keeptime) . md5($expiretime) . $tourists['token'])) {
                return false;
            }
        } else {
            return false;
        }

        $tourists['user_id']  = $tourists['id'] . '||tourists';
        $tourists['username'] = $tourists['nickname'];
        unset($tourists['token']);

        return $tourists;
    }

    /**
     * 获取用户的未读消息->获取他的会话->获取会话中的非他自己发送的未读消息
     * @param string $user_id   带标识符的用户id
     * @param bool   $is_latest 是否只获取用户未链接websocket时的消息
     * @return string
     */
    public static function get_unread_messages($user_id, $is_latest = false)
    {
        $new_msg = '';

        $user = self::user_info($user_id);

        $session_list = Db::name('fastchat_session')->where(function ($query) use ($user_id) {
            $query->where('user_id', $user_id);
        })->whereOr(function ($query) use ($user) {
            $query->where('session_user_id', $user['id'])->where('session_type', $user['session_type']);
        })
            ->order('createtime desc')
            ->select();
        // 查询当前用户发送的未读消息条数
        $data = [];
        foreach ($session_list as $key => $value) {

            $session_user = self::session_user($value, $user_id);

            $where['session_id'] = $value['id'];
            $where['sender']     = $session_user;
            $where['status']     = 0;

            if ($is_latest) {
                $where['createtime'] = ['>', time() - 10];
            }

            $new_msg = Db::name('fastchat_record')
                ->where($where)
                ->order('createtime desc')
                ->find();

            if ($new_msg) {
                $data = $new_msg;
                break;
            }
        }
        if($data){
            $data['unread_msg_count'] = Db::name('fastchat_record')
                ->where('sender', $session_user)
                ->where('status', 0)
                ->count('id');
        }
        return $data;
    }

    /**
     * 获取会话的会话对象
     * @return string
     */
    public static function session_user($session, $oneself = null)
    {

        if (!$oneself) {
            $oneself = $_SESSION['user_id'];
        }

        if ($oneself == $session['user_id']) {

            switch ($session['session_type']) {
                case '0':
                    $session_user = $session['session_user_id'] . '||user';
                    break;
                case '1':
                    $session_user = $session['session_user_id'] . '||admin';
                    break;
                case '2':
                    $session_user = $session['session_user_id'] . '||tourists';
                    break;
                case '5':
                    $session_user = $session['session_user_id'] . '||service_user';
                    break;

                default:
                    $session_user = $session['session_user_id'] . '||none';
                    break;
            }
        } else {
            $session_user = $session['user_id'];
        }

        return $session_user;
    }

    /**
     * 处理前台搜索框的提示文字
     * @return string
     */
    public static function search_tip_fill($search_type)
    {
        $search_tip = '';

        if ($search_type && strstr($search_type, 'none') === false) {

            $search_type = explode(',', $search_type);

            foreach ($search_type as $value) {
                switch ($value) {
                    case "username":
                        $search_tip .= '用户名/';
                        break;
                    case "usermobile":
                        $search_tip .= '手机号/';
                        break;
                    case "userid":
                        $search_tip .= '用户ID/';
                        break;
                    case "nickname":
                        $search_tip .= '用户昵称/';
                        break;
                    default:
                        $search_tip .= '未知/';
                        break;
                }
            }
        }

        if (!$search_tip) {
            $search_tip = '搜索其实很简单';
        } else {
            $search_tip = '搜索' . trim($search_tip, '/') . '发起会话';
        }

        return $search_tip;
    }

    /*
     * 检查/过滤变量
     */
    public static function check_variable(&$variable)
    {
        $variable = htmlspecialchars($variable);
        $variable = stripslashes($variable); // 删除反斜杠
        $variable = addslashes($variable); // 转义特殊符号
        $variable = trim($variable); // 去除字符两边的空格
    }
}